package com.wujunshen.update;

import static com.wujunshen.enumation.RequestMethod.GET;
import static com.wujunshen.enumation.RequestMethod.HEAD;
import static org.apache.http.util.TextUtils.isEmpty;

import com.wujunshen.exception.MyException;
import com.wujunshen.utils.Address;
import com.wujunshen.utils.RequestSender;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.HashMap;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.elasticsearch.SpecialPermission;

/**
 * @author frank woo(吴峻申) <br>
 * email:<a href="mailto:frank_wjs@hotmail.com">frank_wjs@hotmail.com</a> <br>
 * @date 2022/8/23 23:37<br>
 */
@Slf4j
public abstract class BaseMonitor implements Runnable {
    private final Address address;
    private final Address tryAddress;
    private String lastModified;
    private String eTags;

    BaseMonitor(String location) {
        this.address = new HotUpdateAddress(location, "", GET);
        this.tryAddress = new HotUpdateAddress(location, "", HEAD);
    }

    /**
     * 处理响应
     * @param reader BufferedReader类
     * @throws IOException IO异常
     */
    abstract void processResponse(BufferedReader reader) throws IOException;

    @Override
    public void run() {
        SpecialPermission.check();
        AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
            new RequestSender<Void>() {
                @Override
                public Address getAddress() {
                    return tryAddress;
                }

                @Override
                public Map<String, String> getHeaders() {
                    Map<String, String> result = new HashMap<>(2);

                    if (lastModified != null) {
                        result.put("If-Modified-Since", lastModified);
                    }

                    if (eTags != null) {
                        result.put("If-None-Match", eTags);
                    }
                    return result;
                }

                @Override
                public Void readResult(int statusCode, Map<String, String> headers, HttpEntity httpEntity) {
                    if (statusCode == HttpStatus.SC_OK) {
                        String currentLastModified = headers.get("Last-Modified");
                        String currentEtags = headers.get("ETag");

                        if (isEmpty(currentLastModified) || currentLastModified.equals(lastModified)) {
                            if (isEmpty(currentEtags) || currentEtags.equals(eTags)) {
                                log.info("{} result no changed and skip current request.", address.getDomain());
                            } else {
                                log.info("{} update dictionary.", address.getDomain());
                                lastModified = currentLastModified;
                                eTags = currentEtags;
                                updateDictionary();
                            }
                        } else {
                            log.info("{} update dictionary.", address.getDomain());
                            lastModified = currentLastModified;
                            eTags = currentEtags;
                            updateDictionary();
                        }
                    } else if (statusCode == HttpStatus.SC_NOT_MODIFIED) {
                        log.info("{} result no changed and skip current request.", address.getDomain());
                    } else {
                        log.info("{} status code[{}]", address.getDomain(), statusCode);
                    }

                    return null;
                }
            }.send();

            return null;
        });
    }

    private void updateDictionary() {
        SpecialPermission.check();
        AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
            log.info("-----------updateDictionary: begin--------------");
            new RequestSender<Void>() {
                @Override
                public Address getAddress() {
                    return address;
                }

                @Override
                public Void readResult(int statusCode, Map<String, String> headers, HttpEntity httpEntity) {
                    try (BufferedReader reader = new BufferedReader(
                            new InputStreamReader(httpEntity.getContent(), StandardCharsets.UTF_8))) {
                        processResponse(reader);
                    } catch (IOException e) {
                        throw new MyException("hanlp-hot-update.cfg.xml read fail.", e);
                    }

                    return null;
                }
            }.send();

            return null;
        });
    }
}
